package xin.marcher.wind.process.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import xin.marcher.framework.common.exception.BusinessException;
import xin.marcher.framework.common.exception.GlobalCodeEnum;
import xin.marcher.framework.common.util.log.LoggerFormat;
import xin.marcher.wind.process.dao.TradePlatformBizDAO;
import xin.marcher.wind.process.dao.TradePlatformBizProcessArrangeDAO;
import xin.marcher.wind.process.dao.TradePlatformProcessDAO;
import xin.marcher.wind.process.domain.entity.TradePlatformBizDO;
import xin.marcher.wind.process.domain.entity.TradePlatformBizProcessArrangeDO;
import xin.marcher.wind.process.domain.entity.TradePlatformProcessDO;
import xin.marcher.wind.process.domain.request.TradePlatformBizRequest;
import xin.marcher.wind.process.domain.vo.TradePlatformBizVO;
import xin.marcher.wind.process.dto.BizProcessArrangeDTO;
import xin.marcher.wind.process.dto.BizProcessDTO;
import xin.marcher.wind.process.dto.BizProcessNodeDTO;
import xin.marcher.wind.process.enums.ProcessErrorCodeEnum;
import xin.marcher.wind.process.service.TradePlatformBizService;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 *
 * 
 * @version 1.0
 */
@Slf4j
@Service
public class TradePlatformBizServiceImpl implements TradePlatformBizService {

    @Resource
    private TradePlatformBizDAO bizDAO;

    @Resource
    private TradePlatformBizProcessArrangeDAO bizProcessArrangeDAO;

    @Resource
    private TradePlatformProcessDAO tradePlatformProcessDAO;

    @Override
    public void release(String bizId) {

        // 1、查询业务线信息
        TradePlatformBizDO seller = bizDAO.getOne(bizId);
        if(null == seller) {
            throw new BusinessException(ProcessErrorCodeEnum.BIZ_IS_EMPTY);
        }

        // 2、查询业务线的编排的流程
        List<TradePlatformBizProcessArrangeDO> processArrange = bizProcessArrangeDAO.listByBizId(bizId);
        if(CollectionUtils.isNotEmpty(processArrange)) {
            log.info(LoggerFormat.build()
                    .remark("发送广播消息，通知订单系统加载业务线编排流程")
                    .data("bizId", bizId)
                    .finish());

            // 3、发送rocketmq广播消息通知订单系统
            // TODO 待优化
//            defaultProducer.sendMessage(RocketMqConstant.PLATFORM_BIZ_PROCESS_ARRANGE_RELEASE_TOPIC, bizId);
        }
        else {
            log.info(LoggerFormat.build()
                    .remark("该业务线没有自定义编排流程")
                    .data("bizId", bizId)
                    .finish());
        }
    }

    @Override
    public BizProcessArrangeDTO getBizProcessArrange(String bizId) {
        // 1、查询业务线信息
        TradePlatformBizDO biz = bizDAO.getOne(bizId);
        if (null == biz) {
            log.info(LoggerFormat.build()
                    .remark("查询不到业务线")
                    .data("bizId", bizId)
                    .finish());
            return null;
        }

        // 2、查询业务线的编排的流程
        List<TradePlatformBizProcessArrangeDO> processArranges = bizProcessArrangeDAO.listByBizId(bizId);
        if (CollectionUtils.isEmpty(processArranges)) {
            log.info(LoggerFormat.build()
                    .remark("该业务线没有自定义编排流程")
                    .data("bizId", bizId)
                    .finish());
            return null;
        }

        // 3、组装返参
        return buildSellerProcessArrangeDTO(biz, processArranges);
    }

    @Override
    public List<BizProcessArrangeDTO> listAllBizProcessArrange() {
        // 1、查询业务线的编排的流程
        List<TradePlatformBizProcessArrangeDO> processArranges = bizProcessArrangeDAO.list();
        if (CollectionUtils.isEmpty(processArranges)) {
            log.info(LoggerFormat.build()
                    .remark("暂无业务线编排过流程！")
                    .finish());
            return null;
        }

        // 2、按照bizId进行分组
        Map<String, List<TradePlatformBizProcessArrangeDO>> mapByBizId =
                processArranges.stream().collect(Collectors.groupingBy(TradePlatformBizProcessArrangeDO::getBizId));

        // 3、查询业务线信息
        List<String> bizIds = mapByBizId.keySet().stream().collect(Collectors.toList());
        List<TradePlatformBizDO> sellers = bizDAO.listByBizId(bizIds);
        Map<String, TradePlatformBizDO> bizMap = sellers.stream().collect(Collectors.toMap(TradePlatformBizDO::getBizId, c -> c));

        List<BizProcessArrangeDTO> result = new ArrayList<>(bizIds.size());
        for(Map.Entry<String, List<TradePlatformBizProcessArrangeDO>> entry : mapByBizId.entrySet()) {
            String bizId = entry.getKey();
            List<TradePlatformBizProcessArrangeDO> processArrangesBySeller = entry.getValue();
            result.add(buildSellerProcessArrangeDTO(bizMap.get(bizId), processArrangesBySeller));
        }
        return result;
    }

    /**
     * 构造业务线流程name
     */
    private String buildBizProcessName(String bizId, String processName) {
        return bizId + "#" + processName;
    }

    private BizProcessArrangeDTO buildSellerProcessArrangeDTO(TradePlatformBizDO seller,
                                                              List<TradePlatformBizProcessArrangeDO> processArranges
    ) {
        // 构造返参
        BizProcessArrangeDTO result = new BizProcessArrangeDTO();
        result.setBizId(seller.getBizId());
        result.setBizName(seller.getBizName());

        // 按照processId进行分组
        Map<Long, List<TradePlatformBizProcessArrangeDO>> mapByProcessId =
                processArranges.stream().collect(Collectors.groupingBy(TradePlatformBizProcessArrangeDO::getProcessId));

        // 查询processIds对应的Process
        List<Long> processIds = mapByProcessId.keySet().stream().collect(Collectors.toList());
        List<TradePlatformProcessDO> processes = tradePlatformProcessDAO.listByIds(processIds);
        Map<Long, TradePlatformProcessDO> processMap = processes.stream().collect(Collectors.toMap(TradePlatformProcessDO::getId, c -> c));

        // 遍历map
        List<BizProcessDTO> processDTOs = new ArrayList<>(mapByProcessId.size());
        for (Map.Entry<Long, List<TradePlatformBizProcessArrangeDO>> entry : mapByProcessId.entrySet()) {
            Long processId = entry.getKey();
            TradePlatformProcessDO process = processMap.get(processId);
            // 构造process
            BizProcessDTO processDTO = new BizProcessDTO();
            processDTO.setName(buildBizProcessName(seller.getBizId(),process.getName()));
            processDTO.setShowName(process.getShowName());
            processDTOs.add(processDTO);

            // 构造node
            List<BizProcessNodeDTO> nodeDTOs = new ArrayList<>(entry.getValue().size());
            for (TradePlatformBizProcessArrangeDO processNode : entry.getValue()) {
                BizProcessNodeDTO nodeDTO = new BizProcessNodeDTO();
                nodeDTO.setName(processNode.getName());
                nodeDTO.setShowName(processNode.getShowName());
                nodeDTO.setClazzName(processNode.getChosenImplClazzName());
                nodeDTOs.add(nodeDTO);
            }
            processDTO.setNodes(nodeDTOs);
        }
        result.setProcesses(processDTOs);
        return result;

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public TradePlatformBizVO addBiz(TradePlatformBizRequest tradePlatformBizRequest) {
        Assert.notNull(tradePlatformBizRequest, "入参不能为空");
        String bizId = tradePlatformBizRequest.getBizId();
        String bizName = tradePlatformBizRequest.getBizName();

        Assert.notNull(bizId, "接入业务线ID不能为空");
        Assert.notNull(bizName, "接入业务线名称不能为空");

        TradePlatformBizDO tradePlatformBizDO = new TradePlatformBizDO();
        tradePlatformBizDO.setBizId(bizId);
        tradePlatformBizDO.setBizName(bizName);
        bizDAO.save(tradePlatformBizDO);

        TradePlatformBizVO result = new TradePlatformBizVO();
        result.setBizId(bizId);
        result.setBizName(bizName);
        return result;
    }

    @Override
    public TradePlatformBizVO getBiz(String bizId) {
        Assert.notNull(bizId, "接入业务线ID不能为空");
        TradePlatformBizDO tradePlatformBizDO = bizDAO.getOne(bizId);
        if(tradePlatformBizDO != null) {
            TradePlatformBizVO result = new TradePlatformBizVO();
            result.setBizId(bizId);
            result.setBizName(tradePlatformBizDO.getBizName());
            return result;
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TradePlatformBizVO editBiz(TradePlatformBizRequest tradePlatformBizRequest) {
        Assert.notNull(tradePlatformBizRequest, "入参不能为空");
        String bizId = tradePlatformBizRequest.getBizId();
        String bizName = tradePlatformBizRequest.getBizName();

        Assert.notNull(bizId, "接入业务线ID不能为空");
        Assert.notNull(bizName, "接入业务线名称不能为空");

        TradePlatformBizDO tradePlatformBizDO = bizDAO.getOne(bizId);
        if(tradePlatformBizDO == null) {
            throw new BusinessException(GlobalCodeEnum.GL_SERVER_ERROR.getRealCode(), "接入业务线{}不存在", bizId);
        }

        if(StringUtils.isNotEmpty(bizName)) {
            tradePlatformBizDO.setBizName(tradePlatformBizRequest.getBizName());
        }
        bizDAO.updateById(tradePlatformBizDO);

        TradePlatformBizVO result = new TradePlatformBizVO();
        result.setBizId(bizId);
        result.setBizName(tradePlatformBizDO.getBizName());
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteBiz(String bizId) {
        Assert.notNull(bizId, "接入业务线ID不能为空");

        // 检查是否存在关联的流程编排配置信息
        List<TradePlatformBizProcessArrangeDO> list = bizProcessArrangeDAO.listByBizId(bizId);
        if(list != null && !list.isEmpty()) {
            throw new BusinessException("当前流程定义存在关联的业务线流程编排配置数据，不能删除");
        }

        return bizDAO.deleteBiz(bizId);
    }

}
